﻿
using System;
using System.Collections.Generic;
using Test30.Core;

namespace Test30.Engine
{
    public class Monster : Entity,IRace
    {

        public static IList<Monster> AddRandom(Dungeon dungeon, int level, Vec startPos,int depth)
        {
            Race race = Race.Random(dungeon, level, true);
            List<Monster> monsters = new List<Monster>();

            Monster monster = new Monster(startPos, race);
            monsters.Add(monster);
            dungeon.Entities.Add(monster, depth);
            ObjectPool.Get?.Spawn(monster, depth);


            // generate friends
            if (race.NumberInGroup > 1)
            {
                int numMonsters = Rng.TriangleInt(race.NumberInGroup, race.NumberInGroup / 3);
                int tries = 0;
                while ((monsters.Count < numMonsters) && (tries < 100))
                {
                    tries++;
                    if (dungeon.TryFindOpenAdjacent(Rng.Item(monsters).Position, out var pos))
                    {
                        // found one, so put another there
                        Monster buddy = new Monster(pos, race);
                        monsters.Add(buddy);
                        dungeon.Entities.Add(buddy,depth);

                        ObjectPool.Get?.Spawn(buddy, depth);
                    }
                }
            }
            return monsters;
        }
        public override Attack GetAttack(Entity defender)
        {
            // pick one randomly
            return Rng.Item(Race.Attacks);
        }

        public Race Race { get; }
        public override int LightRadius => Race.LightRadius;
        public override string Name => Race.Name;
        public Monster(Vec pos, Race race) : base(pos, race.Speed, race.Health.Roll())
        {
            Race = race;
            SetBehavior(race.CreateBehavior(this));
            Energy.Randomize();
        }

        public T GetMoveInstance<T>() where T : new()
        {
            Type type = typeof(T);

            // lazy create
            if (!_moveInstances.ContainsKey(type)) _moveInstances[type] = new T();

            return (T)_moveInstances[type];
        }

        public bool IsOccupiedByOtherMonster(Vec move, Entity target)
        {
            Entity occupier = Dungeon.Entities.GetAt(Position + move);
            if ((occupier != null) && (occupier != this) && (occupier != target))
            {
                return true;
            }

            return false;
        }

        protected override bool OnDie(Action action)
        {
            // drop stuff
            Race.PlaceDrop(Dungeon, Position);

            // monsters can die
            return true;
        }
        protected override float OnGetResistance(Element element)
        {
            switch (Race.GetResistance(element))
            {
                case RaceResist.Immune: return 0.0f;
                case RaceResist.VeryStrong: return 0.25f;
                case RaceResist.Strong: return 0.5f;
                case RaceResist.None: return 1.0f;
                case RaceResist.Weak: return 2.0f;
                case RaceResist.VeryWeak: return 4.0f;
                default: throw new UnexpectedEnumValueException(Race.GetResistance(element));
            }
        }
        #region INoun Members

        public override string NounText
        {
            get
            {
                // don't add an article to a proper noun
                if (Race.IsUnique) return Race.Name;

                return "the " + Race.Name;
            }
        }

        public override Person Person => Person.Third;

        //### bob: handle gender and proper nouns
        public override string Pronoun => "it";

        public override string Possessive => "its";

        #endregion


        private readonly Dictionary<Type, object> _moveInstances = new Dictionary<Type, object>();
    }
}
